package com.collect.senegal.zhiHelper;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import androidx.ads.identifier.AdvertisingIdClient;
import androidx.ads.identifier.AdvertisingIdInfo;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.collect.senegal.MyApplication;
import com.collect.senegal.zhiGlobal.zhiAppSettings.ZHIProjectConstants;
import com.collect.senegal.zhiUtils.SPUtils;
import com.collect.senegal.zhiUtils.StringUtil;

import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class ZHIAdvertIDHelper {

    private static final String TAG = ZHIAdvertIDHelper.class.getSimpleName();

    private static final int GAID_FETCH_TYPE_INTERFACE = 0;

    private static final int GAID_FETCH_TYPE_CLIENT = 100;

    private static final int GAID_FETCH_TYPE_FUTURE = 200;

    private String mGoogleAdvertIdFromInterface = "";

    private String mGoogleAdvertIdFromFuture = "";

    private String mGoogleAdvertIdFromClient = "";

    private int mGoogleAdvertIdFetchType = GAID_FETCH_TYPE_INTERFACE;

    private static final ZHIAdvertIDHelper instance = new ZHIAdvertIDHelper();

    public static ZHIAdvertIDHelper getInstance() {
        return instance;
    }

    public ZHIAdvertIDHelper() {
        String gAdverIdFromInterface = StringUtil.safeString(SPUtils.getInstance().getString(ZHIProjectConstants.GOOGLE_ADVERT_ID));
        Log.d(TAG, "gAdverIdFromInterface: " + gAdverIdFromInterface);

        String gAdverIdFromFutrue = StringUtil.safeString(SPUtils.getInstance().getString(ZHIProjectConstants.GOOGLE_ADVERT_ID_FUTURE));
        Log.d(TAG, "gAdverIdFromFutrue: " + gAdverIdFromFutrue);

        String gAdverIdFromClient = StringUtil.safeString(SPUtils.getInstance().getString(ZHIProjectConstants.GOOGLE_ADVERT_ID_CLIENT));
        Log.d(TAG, "gAdverIdFromClient: " + gAdverIdFromClient);

        setGoogleAdvertIdFromInterface(gAdverIdFromInterface);
        setGoogleAdvertIdFromFutureCall(gAdverIdFromFutrue);
        setGoogleAdvertIdFromClient(gAdverIdFromClient);
    }

    public void setGoogleAdvertIdFromInterface(String googleAdvertId) {
        mGoogleAdvertIdFromInterface = StringUtil.safeString(googleAdvertId).toLowerCase();
        //保存
        SPUtils.getInstance().put(ZHIProjectConstants.GOOGLE_ADVERT_ID, mGoogleAdvertIdFromInterface, true);
    }

    public void setGoogleAdvertIdFromFutureCall(String googleAdvertId) {
        mGoogleAdvertIdFromFuture = StringUtil.safeString(googleAdvertId).toLowerCase();
        //保存
        SPUtils.getInstance().put(ZHIProjectConstants.GOOGLE_ADVERT_ID_FUTURE, mGoogleAdvertIdFromFuture, true);
    }

    public void setGoogleAdvertIdFromClient(String googleAdvertId) {
        mGoogleAdvertIdFromClient = StringUtil.safeString(googleAdvertId).toLowerCase();
        //保存
        SPUtils.getInstance().put(ZHIProjectConstants.GOOGLE_ADVERT_ID_CLIENT, mGoogleAdvertIdFromClient, true);
    }

    public boolean isRealGoogleAdvertId() {
        return !TextUtils.isEmpty(getGoogleAdvertId());
    }

    public String getGoogleAdvertId() {
        mGoogleAdvertIdFromInterface = StringUtil.safeString(mGoogleAdvertIdFromInterface);
        //测试老接口
//        mGoogleAdvertIdFromClient = StringUtil.safeString(mGoogleAdvertIdFromClient);
//
//        if (mGoogleAdvertIdFromInterface.equalsIgnoreCase(mGoogleAdvertIdFromClient)) {
//            return mGoogleAdvertIdFromInterface;
//        }
//
//        if (TextUtils.isEmpty(mGoogleAdvertIdFromInterface)) {
//            return mGoogleAdvertIdFromClient;
//        }

        return mGoogleAdvertIdFromInterface;
    }

    public void init() {
        try {
            if (!TextUtils.isEmpty(getGoogleAdvertId())) {
                return;
            }

            new Thread(new FetchGoogleAdvertIdFomInterfaceRunnable()).start();

            if (mGoogleAdvertIdFetchType == GAID_FETCH_TYPE_CLIENT) {
                new Thread(new FetchGoogleAdvertIdFromClientRunnable()).start();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class FetchGoogleAdvertIdFomInterfaceRunnable implements Runnable {
        @Override
        public void run() {
            try {
                String gid = ZHIAdvertIDHelper.getGoogleAdIdFromInterface();
                ZHIAdvertIDHelper.getInstance().setGoogleAdvertIdFromInterface(gid);
                Log.d(TAG, "getGoogleAdIdFromInterface: " + gid);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    static class FetchGoogleAdvertIdFromClientRunnable implements Runnable {
        @Override
        public void run() {
            try {
                ZHIAdvertIDHelper.getInstance().getGoogleAdIdFromClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 这个方法是耗时的，不能在主线程调用
     */
    public static String getGoogleAdIdFromInterface() throws Exception {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            return "Cannot call in the main thread, You must call in the other thread";
        }
        PackageManager pm = MyApplication.getAppContext().getPackageManager();
        pm.getPackageInfo("com.android.vending", 0);
        AdvertisingConnection connection = new AdvertisingConnection();
        Intent intent = new Intent("com.google.android.gms.ads.identifier.service.START");
        intent.setPackage("com.google.android.gms");
        if (MyApplication.getAppContext().bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
            try {
                AdvertisingInterface adInterface = new AdvertisingInterface(connection.getBinder());
                return StringUtil.safeString(adInterface.getId());
            } finally {
                MyApplication.getAppContext().unbindService(connection);
            }
        }
        return "";
    }

    private static final class AdvertisingConnection implements ServiceConnection {
        boolean retrieved = false;
        private final LinkedBlockingQueue<IBinder> queue = new LinkedBlockingQueue<>(1);

        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                this.queue.put(service);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }

        public void onServiceDisconnected(ComponentName name) {
        }

        IBinder getBinder() throws InterruptedException {
            if (this.retrieved)
                throw new IllegalStateException();
            this.retrieved = true;
            return this.queue.take();
        }
    }

    private static final class AdvertisingInterface implements IInterface {
        private final IBinder binder;

        AdvertisingInterface(IBinder pBinder) {
            binder = pBinder;
        }

        public IBinder asBinder() {
            return binder;
        }

        public String getId() throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            String id;
            try {
                data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
                binder.transact(1, data, reply, 0);
                reply.readException();
                id = reply.readString();
            } finally {
                reply.recycle();
                data.recycle();
            }
            return id;
        }

        public boolean isLimitAdTrackingEnabled(boolean paramBoolean)
                throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            boolean limitAdTracking;
            try {
                data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
                data.writeInt(paramBoolean ? 1 : 0);
                binder.transact(2, data, reply, 0);
                reply.readException();
                limitAdTracking = 0 != reply.readInt();
            } finally {
                reply.recycle();
                data.recycle();
            }
            return limitAdTracking;
        }
    }

    public void getGoogleAdIdFromFutrue() {
        try {
            if (AdvertisingIdClient.isAdvertisingIdProviderAvailable(MyApplication.getAppContext())) {
                ListenableFuture<AdvertisingIdInfo> advertisingIdInfoListenableFuture =
                        AdvertisingIdClient.getAdvertisingIdInfo(MyApplication.getAppContext());
                Futures.addCallback(advertisingIdInfoListenableFuture, new FutureCallback<AdvertisingIdInfo>() {
                    @Override
                    public void onSuccess(@NullableDecl AdvertisingIdInfo result) {
                        if (result != null) {
                            String gid = StringUtil.safeString(result.getId());
                            boolean isLimitTrackingEnabled = result.isLimitAdTrackingEnabled();

                            setGoogleAdvertIdFromFutureCall(gid);

                            Log.d(TAG, "determineAdvertisingInfo: " + gid);
                            Log.d(TAG, "determineAdvertisingInfo: " + isLimitTrackingEnabled);
                        }
                    }

                    @Override
                    public void onFailure(@NotNull Throwable t) {
                        Log.e("MY_APP_TAG",
                                "Failed to connect to Advertising ID provider.");
                        setGoogleAdvertIdFromFutureCall("");
                    }
                }, Executors.newSingleThreadExecutor());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getGoogleAdIdFromClient() {
        try {
            if (Looper.getMainLooper() == Looper.myLooper()) {
                Log.d(TAG, "Cannot call in the main thread, You must call in the other thread");
            }

            com.google.android.gms.ads.identifier.AdvertisingIdClient.Info adsInfo = com.google.android.gms.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(MyApplication.getAppContext());

            String gid = StringUtil.safeString(adsInfo.getId());
            boolean isLimitTrackingEnabled = adsInfo.isLimitAdTrackingEnabled();

            setGoogleAdvertIdFromClient(gid);

            Log.d(TAG, "getGoogleAdIdFromClient: " + gid);
            Log.d(TAG, "getGoogleAdIdFromClient: " + isLimitTrackingEnabled);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}